package be.rivendale.mathematics;

import static be.rivendale.mathematics.MathematicalAssert.assertPointEquals;
import static be.rivendale.mathematics.MathematicalAssert.assertVectorEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import org.junit.Test;

public class PlaneTest {
    @Test(expected = IllegalArgumentException.class)
    public void constructorByThreePointsThrowsIllegalArgumentExceptionIfPointAIsNull() throws Exception {
        new Plane(null, new Triple(1, 2, 3), new Triple(8, 7, 6));
    }

    @Test(expected = IllegalArgumentException.class)
    public void constructorByThreePointsThrowsIllegalArgumentExceptionIfPointBIsNull() throws Exception {
        new Plane(new Triple(1, 2, 3), null, new Triple(8, 7, 6));
    }

    @Test(expected = IllegalArgumentException.class)
    public void constructorByThreePointsThrowsIllegalArgumentExceptionIfPointCIsNull() throws Exception {
        new Plane(new Triple(1, 2, 3), new Triple(8, 7, 6), null);
    }

    @Test(expected = IllegalArgumentException.class)
    public void constructorThrowsIllegalArgumentExceptionWhenAllPointAreLinear() throws Exception {
        new Plane(new Triple(1, 2, 3), new Triple(4, 5, 6), new Triple(7, 8, 9));
    }

    @Test(expected = IllegalArgumentException.class)
    public void constructorThrowsIllegalArgumentExceptionWhenPointAAndPointBAreEqual() throws Exception {
        new Plane(new Triple(1, 2, 3), new Triple(1, 2, 3), new Triple(7, 8, 9));
    }

    @Test(expected = IllegalArgumentException.class)
    public void constructorThrowsIllegalArgumentExceptionWhenPointAAndPointCAreEqual() throws Exception {
        new Plane(new Triple(1, 2, 3), new Triple(4, 5, 6), new Triple(1, 2, 3));
    }

    @Test(expected = IllegalArgumentException.class)
    public void constructorThrowsIllegalArgumentExceptionWhenPointBAndPointCAreEqual() throws Exception {
        new Plane(new Triple(1, 2, 3), new Triple(7, 8, 9), new Triple(7, 8, 9));
    }

    @Test
    public void constructorByThreePointsSetsFirstSetsPointC() throws Exception {
        Plane plane = new Plane(new Triple(1, 2, 3), new Triple(1, 8, 5), new Triple(5, 7, 6));
        assertPointEquals(new Triple(5, 7, 6), plane.getC());
    }

    @Test
    public void constructorByThreePointsSetsPointA() throws Exception {
        Plane plane = new Plane(new Triple(1, 2, 3), new Triple(1, 8, 5), new Triple(5, 7, 6));
        assertPointEquals(new Triple(1, 2, 3), plane.getA());
    }

    @Test
    public void constructorByThreePointsSetsPointB() throws Exception {
        Plane plane = new Plane(new Triple(1, 2, 3), new Triple(1, 8, 5), new Triple(5, 7, 6));
        assertPointEquals(new Triple(1, 8, 5), plane.getB());
    }

    @Test
    public void normalReturnsUnnormalizedNormalVectorOfThePlane() throws Exception {
        Plane plane = new Plane(new Triple(1, 2, 3), new Triple(1, 8, 5), new Triple(5, 7, 6));
        assertVectorEquals(new Triple(8, 8, -24), plane.normal());
    }

    @Test
    public void containsReturnsFalseIfPointDoesNotLieOnPlane() throws Exception {
        Plane plane = new Plane(new Triple(2, -5, 2), new Triple(3, 1, -5), new Triple(-2, 0, 0));
        assertFalse(plane.contains(new Triple(0, 3, -1)));
    }

    @Test
    public void containsReturnsTrueIfPointLiesOnPlane() throws Exception {
        Plane plane = new Plane(new Triple(2, -5, 2), new Triple(3, 1, -5), new Triple(-2, 0, 0));
        assertTrue(plane.contains(new Triple(-4.874184, -1.808299, 4.150179)));
    }

    @Test
    public void containsReturnsTrueIfPointIsEqualToA() throws Exception {
        Plane plane = new Plane(new Triple(2, -5, 2), new Triple(3, 1, -5), new Triple(-2, 0, 0));
        plane.contains(new Triple(2, -5, 2));
    }

    @Test
    public void pointOnPlaneReturnsNewPointOnThePlane() throws Exception {
        Plane plane = new Plane(new Triple(-1, -3, -5), new Triple(0, 2, 0), new Triple(3, -2, -3));
        Point point = plane.pointOnPlane(0.5, 0.75);
        assertPointEquals(new Triple(2.5, 0.25, -1), point);
    }

    @Test
    public void pointOnPlaneReturnsPointEqualToAWhenPassingZeroAsParameters() throws Exception {
        Plane plane = new Plane(new Triple(5, -3, 2), new Triple(-1, 6, 1), new Triple(0, 1, 5));
        Point point = plane.pointOnPlane(0, 0);
        assertPointEquals(new Triple(5, -3, 2), point);
    }
}
